package com.mytx.notify.redisMessageQueue;

import com.alibaba.fastjson.JSONObject;
import com.mytx.common.constant.Constant;
import com.mytx.common.utils.DateUtils;
import com.mytx.mapper.AdvertisementMapper;
import com.mytx.pojo.Advertisement;
import net.nettime.mobileimsdk.server.netty.MBObserver;
import net.openmob.mobileimsdk.server.utils.LocalSendHelper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.connection.Message;
import org.springframework.data.redis.connection.MessageListener;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import java.math.BigDecimal;
import java.nio.charset.Charset;
import java.util.*;


@SuppressWarnings({"Duplicates", "SpringJavaInjectionPointsAutowiringInspection"})
@Component
public class Receiver implements MessageListener {
    private static final Logger logger = LoggerFactory.getLogger(Receiver.class);

    @Autowired
    RedisTemplate redisTemplate;

    @Autowired
    AdvertisementMapper advertisementMapper;

    @Override
    public void onMessage(Message message, byte[] pattern) {

        String deserialize = new String(message.getBody(), Charset.forName("UTF-8"));
        String channel = new String(message.getChannel(), Charset.forName("UTF-8"));
        logger.info("onMessage:channel{},deserialize:{}", channel, deserialize);
        com.mytx.pojo.Message notify = new com.mytx.pojo.Message();//Motify 和自定义的实体类Message 字段一样，前端可以用Message 接收
        List<String> userIdList = new ArrayList<>();
        notify.setCreated(new Date());
        notify.setNick("系统消息");
        JSONObject info = JSONObject.parseObject(deserialize);
        String liveRoomId = "";
        if (info.containsKey("liveRoomId")) {
            liveRoomId = (String) info.remove("liveRoomId");
        }
        switch (channel) {
            case Constant.NOTIFY_OFFER_FAIL:
                userIdList = info.getJSONArray("userIdList").toJavaList(String.class);
                notify.setContent(info.getJSONObject("advertisement").toJSONString());
                notify.setType(Constant.PUSH_MESSAGE_OFFER_FAIL);
                pushMessage(userIdList, notify,Constant.SYSTEM_MESSAGE);

                break;
            case Constant.NOTIFY_ADVERTISEMENT_NEED_SET_SHOW_CONTENT:
                notify.setContent(info.getJSONObject("advertisement").toJSONString());//因为在app 端没有forward 表，所以以json格式存content字段，方便存储
                userIdList.add((String) info.remove("uId"));
                notify.setType(Constant.PUSH_MESSAGE_OFFER_SUCCESS);
                pushMessage(userIdList, notify,Constant.SYSTEM_MESSAGE);
                break;
            case Constant.NOTIFY_PERSON_RECEIVED_DONATION: //个人收到捐赠
                notify.setContent(info.getJSONObject("donation").toJSONString());//因为在app 端没有donation 表，所以以json格式存content字段，方便存储
                userIdList.add((String) info.remove("uId"));
                notify.setType(Constant.PUSH_MESSAGE_PERSON_RECEIVED_DONATION);
                notify.setVisible(Constant.MESSAGE_VISIBLE);
                pushMessage(userIdList, notify,Constant.SYSTEM_MESSAGE);
                break;

            case Constant.NOTIFY_PERSON_RECEIVED_FORWARD: //个人收到转赠
                notify.setContent(info.getJSONObject("forward").toJSONString());//因为在app 端没有forward 表，所以以json格式存content字段，方便存储
                userIdList.add((String) info.remove("uId"));
                notify.setVisible(Constant.MESSAGE_VISIBLE);
                notify.setType(Constant.PUSH_MESSAGE_PERSON_RECEIVED_FORWARD);
                pushMessage(userIdList, notify,Constant.SYSTEM_MESSAGE);

                break;
            case Constant.NOTIFY_SYNC_USER_INFO://通知用户更新数据
                notify.setType(Constant.PUSH_MESSAGE_UPDATE_USER_INFO);
                if (info.containsKey("userIdList")) {
                    userIdList = info.getJSONArray("userIdList").toJavaList(String.class);
                } else if (info.containsKey("uId")) {
                    userIdList.add(info.getString("uId"));
                }
                if (userIdList.size() > 0) {
                    pushMessage(userIdList, notify,Constant.SYSTEM_MESSAGE);
                }
                break;
            //==================================================直播间相关的=================================================================

            case Constant.NOTIFY_LIVE_TO_START:
                notify.setType(Constant.LIVE_ROOM_PUSH_MESSAGE_LIVE_START);
                if (info.size() != 0) {
                    notify.setExtraData(info);
                }
                pushMessage(liveRoomId, notify);
                break;
            case Constant.NOTIFY_LIVE_TO_STOP:
                notify.setType(Constant.LIVE_ROOM_PUSH_MESSAGE_LIVE_STOP);
                if (info.size() != 0) {
                    notify.setExtraData(info);
                }
                pushMessage(liveRoomId, notify);

                break;
            case Constant.NOTIFY_LIVE_RECEIVED_MULCT:
                notify.setType(Constant.LIVE_ROOM_PUSH_MESSAGE_RECEIVED_MULCT);
                if (info.size() != 0) {
                    notify.setExtraData(info);
                }
                pushMessage(liveRoomId, notify);

                break;
            case Constant.NOTIFY_LIVE_RECEIVED_REWARD:
                notify.setType(Constant.LIVE_ROOM_PUSH_MESSAGE_RECEIVED_REWARD);
                if (info.size() != 0) {
                    notify.setExtraData(info);
                }
                pushMessage(liveRoomId, notify);

                break;
            case Constant.NOTIFY_LIVE_RECEIVED_OFFER:
                notify.setType(Constant.LIVE_ROOM_PUSH_MESSAGE_RECEIVED_OFFER);
                if (info.size() != 0) {
                    notify.setExtraData(info);
                }
                pushMessage(liveRoomId, notify);

                break;
            case Constant.NOTIFY_LIVE_RECEIVED_DONATION:
                notify.setType(Constant.LIVE_ROOM_PUSH_MESSAGE_RECEIVED_DONATION);
                if (info.size() != 0) {
                    notify.setExtraData(info);
                }
                pushMessage(liveRoomId, notify);

                break;
            case Constant.NOTIFY_ADVERTISEMENT_CHANGE:
                notify.setType(Constant.LIVE_ROOM_PUSH_MESSAGE_ADVERTISEMENT_CHANGE);
                if (info.size() != 0) {
                    notify.setExtraData(info);
                }
                pushMessage(liveRoomId, notify);
                break;

//            case Constant.NOTIFY_GENERATE_NEW_ADVERTISEMENT:
//                notify.setType(Constant.LIVE_ROOM_PUSH_MESSAGE_GENERATE_NEW_ADVERTISEMENT);
//                break;


            case Constant.NOTIFY_MODIFY_ADVERTISEMENT_MAX_PRICE:
                modifyAdvertisementMaxPrice_v1(info);
                break;
            case Constant.NOTIFY_CHATID_CHANGE_INFO:
                notify.setType(Constant.LIVE_ROOM_PUSH_MESSAGE_CHATID_CHANGE);
                Long oldChatId = info.getLong("oldChatId");
                String newChatId = info.getString("newChatId");
                notify.setExtraData(newChatId);
                String oldManger = info.getString("oldManger");
                // pushMessage(notify, oldManger, oldChatId);
                break;


            //========================================= search 服务相关的推送==================================

            case Constant.NOTIFY_PUSH_MESSAGE:
                if (!(info.containsKey("userIdList") || info.containsKey("notify"))) {
                    logger.error("onMessage:userIdList 或者notify为空");
                    return;
                }
                userIdList = info.getJSONArray("userIdList").toJavaList(String.class);
                notify = info.getObject("message", com.mytx.pojo.Message.class);
                pushMessage(userIdList, notify,Constant.SYSTEM_MESSAGE);
                break;
            case Constant.NOTIFY_CHAR_ROOM_MESSAGE:
                com.mytx.pojo.Message chatRoomMessage = info.toJavaObject(com.mytx.pojo.Message.class);
                pushMessage(chatRoomMessage.getToId(), chatRoomMessage);
                break;

        }

    }

    private void pushMessage(String liveRoomId, com.mytx.pojo.Message notify) {
        String key = Constant.LIVE_ROOM_MEMBER + liveRoomId;
        Long size = redisTemplate.opsForList().size(key);
        if (size != null && size > 0) {
            List<String> userIdList = redisTemplate.opsForList().range(key, 0, size - 1);
            if (userIdList == null || userIdList.size() == 0) {
                return;
            }
            //聊天室消息，不发送给自己
            String fromId = notify.getFromId();
            userIdList.remove(fromId);
            pushMessage(userIdList, notify,Constant.LIVE_ROOM_MESSAGE);
        }

    }

    private void pushMessage(List<String> userIdList, com.mytx.pojo.Message notify,int messageType) {
        String mesStr = JSONObject.toJSONString(notify);
        logger.info("mesStr:{}",mesStr);
        for (String userId : userIdList) {
            try {
                LocalSendHelper.sendData(userId, JSONObject.toJSONString(notify), true, messageType, new MBObserver() {
                    @Override
                    public void update(boolean success, Object extraObj) {
                        if (success) {
                            logger.info("pushMessage:向用户: {} 推送消息成功 ", userId);
                        } else {
                            logger.error("pushMessage:向用户: {} 推送消息失败 ", userId);
                            // TODO: 2019/6/20 推送消息失败后，缓存到redis中，当用户重连时，再发送 
                            redisTemplate.opsForList().rightPush(Constant.OFF_LINE_MESSAGE_RECORD + userId,notify);
                        }
                    }
                });
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

    }


    /**
     * 如果有历史出价记录，直接重新计算24小内的最高价，
     * 如果没有出价记录，根据当前出价的时间段，和缓存中的各时间段最高价做比较，如果高于缓存中的记录，则替换掉。
     *
     * @param info
     */
    private void modifyAdvertisementMaxPrice_v1(JSONObject info) {
        Advertisement advertisement = info.getObject("advertisement", Advertisement.class);
        Date currentDate = new Date();
        Date startDate = advertisement.getStartDate();
        Date endDate = advertisement.getEndDate();
        String liveRoomId = advertisement.getrId();
        BigDecimal amount = advertisement.getAmount();

        if (info.containsKey("historyAdvertisement")) {
            // Advertisement historyAdvertisement = info.getObject("historyAdvertisement", Advertisement.class);
            Calendar nowCalendar = Calendar.getInstance();
            nowCalendar.add(Calendar.HOUR, 1);//增加一小时，
            nowCalendar.set(Calendar.MINUTE, 0);
            nowCalendar.set(Calendar.SECOND, 0);
            nowCalendar.set(Calendar.MILLISECOND, 0);
            //最小开始时间 下一个小时的整点
            Date minStartDate = nowCalendar.getTime();

            nowCalendar.add(Calendar.DATE, 1);//加一天
            Date tomorrowTime = nowCalendar.getTime();

            //每循环一次，增加一个小时，直到和当前出价的广告位开始时间重叠，跳出
            Map<String, Object> maxPriceRecord = new HashMap<>();
            while (minStartDate.before(tomorrowTime)) {
                String maxPriceKey = DateUtils.formatDate(minStartDate, Constant.DATE_HOUR_FORMAT);
                //根据时段，从mysql中查询出当前时段出价最高的广告位，并把它的价格作为最高价，写入缓存
                Advertisement maxPriceAdvertisement = advertisementMapper.selectMaxAmountAdvertisement(liveRoomId, minStartDate, DateUtils.addHour(minStartDate, 1));
                if (maxPriceAdvertisement != null) {
                    maxPriceRecord.put(maxPriceKey, maxPriceAdvertisement.getAmount());
                    //  logger.info("putAdvertisement: maxPriceKey：{},最高价：{}", maxPriceKey, maxPriceAdvertisement.getAmount());
                    redisTemplate.opsForHash().put(Constant.MAX_PRICE_RECORD + liveRoomId, maxPriceKey, maxPriceAdvertisement.getAmount());
                } else {
                    // logger.info("putAdvertisement: 当前时段没有出价记录 maxPriceKey：{},", maxPriceKey);
                    redisTemplate.opsForHash().delete(Constant.MAX_PRICE_RECORD + liveRoomId, maxPriceKey);

                }
                minStartDate = DateUtils.addHour(minStartDate, 1);
            }
            //push 最高价记录给客户端
            com.mytx.pojo.Message notify = new com.mytx.pojo.Message();
            notify.setType(Constant.LIVE_ROOM_PUSH_MESSAGE_ADVERTISEMENT_MAX_PRICE_CHANGE);
            notify.setExtraData(maxPriceRecord);
            pushMessage(liveRoomId, notify);
            return;
        }

        //如果结束时间在24小时以后，则以一天后的时间点作为判断的结束点
        Date addOneDay = DateUtils.addDays(currentDate, 1);
        if (endDate.after(addOneDay)) {
            endDate = addOneDay;
        }
        //循环判断 出价是否高于当前最高价，每循环一次，增加一个小时
        Date addOneHour = startDate;
        while (addOneHour.before(endDate)) {
            String maxPriceKey = DateUtils.formatDate(addOneHour, Constant.DATE_HOUR_FORMAT);
            //先拿出当前时段的最高价，也可能是空的，说明这个时间段没人出价
            Object originalMaxPriceObject = redisTemplate.opsForHash().get(Constant.MAX_PRICE_RECORD + liveRoomId, maxPriceKey);
            if (originalMaxPriceObject == null) {
                // logger.info("putAdvertisement: 该时段没有历史出价记录，设置当前出价做为最高价 maxPriceKey：{}，amount:{}", maxPriceKey, amount);
                redisTemplate.opsForHash().put(Constant.MAX_PRICE_RECORD + liveRoomId, maxPriceKey, amount);
            } else {
                BigDecimal originalMaxPrice = null;
                if (originalMaxPriceObject instanceof BigDecimal) {

                    originalMaxPrice = (BigDecimal) originalMaxPriceObject;
                } else if (originalMaxPriceObject instanceof Integer) {
                    originalMaxPrice = new BigDecimal((Integer) originalMaxPriceObject);
                }
                //如果当前出价 高于之前的价格，把当前出价覆盖掉之前的出价，以此形成新的最高价
                if (originalMaxPrice == null || amount.compareTo(originalMaxPrice) > 0) {
                    //  logger.info("putAdvertisement: 当前出价高于历史最高价，设置当前出价做为最高价 maxPriceKey：{},amount:{},历史出价：{}", maxPriceKey, amount, originalMaxPrice);
                    redisTemplate.opsForHash().put(Constant.MAX_PRICE_RECORD + liveRoomId, maxPriceKey, amount);
                } else {
                    //logger.info("putAdvertisement: 当前出价低于历史出价， maxPriceKey：{},amount:{},历史出价：{}", maxPriceKey, amount, originalMaxPrice);

                }
            }
            //每循环一次，增加一个小时，
            addOneHour = DateUtils.addHour(addOneHour, 1);
        }
        //如果开始时间在一天之后，不查询出价记录push 给前端
        if (startDate.after(addOneDay)) {
            return;
        }
        //push 最高价记录给客户端
        Map maxPriceRecord = redisTemplate.opsForHash().entries(Constant.MAX_PRICE_RECORD + liveRoomId);
        com.mytx.pojo.Message notify = new com.mytx.pojo.Message();
        notify.setType(Constant.LIVE_ROOM_PUSH_MESSAGE_ADVERTISEMENT_MAX_PRICE_CHANGE);
        notify.setExtraData(maxPriceRecord);
        notify.setVisible(Constant.MESSAGE_INVISIBLE);
        pushMessage(liveRoomId, notify);
    }


}
